/*
 * Copyright 2022 Rich yang, 18158898020@189.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

`include "defines.v"

module openrv(
	input wire	clk,
	input wire	rst,

	input wire[`RegBus]	rom_data_i,
	output wire[`RegBus]	rom_addr_o,
	output wire		rom_ce_o,

	input wire[`RegBus]	ram_data_i,
	output wire[`RegBus]	ram_addr_o,
	output wire[`RegBus]	ram_data_o,
	output wire		ram_we_o,
	output wire[3:0]	ram_sel_o,
	output wire		ram_ce_o	
);


wire[`InstAddrBus] pc;
wire[`InstAddrBus] id_pc_i;
wire[`InstBus]	   id_inst_i;


wire[`AluOpBus]		id_aluop_o;
wire[`AluSelBus]	id_alusel_o;
wire[`RegBus]		id_reg1_o;
wire[`RegBus]		id_reg2_o;
wire			id_wreg_o;
wire[`RegAddrBus]	id_wd_o;
wire[`RegBus]		id_inst_o;

wire[`AluOpBus]		ex_aluop_i;
wire[`AluSelBus]	ex_alusel_i;
wire[`RegBus]		ex_reg1_i;
wire[`RegBus]		ex_reg2_i;
wire			ex_wreg_i;
wire[`RegAddrBus]	ex_wd_i;
wire[`RegBus]		ex_inst_i;

wire[`AluOpBus]		ex_aluop_o;
wire[`RegBus]		ex_mem_addr_o;
wire[`RegBus]		ex_reg2_o;

wire			ex_wreg_o;
wire[`RegAddrBus]	ex_wd_o;
wire[`RegBus]		ex_wdata_o;

wire			mem_wreg_i;
wire[`RegAddrBus]	mem_wd_i;
wire[`RegBus]		mem_wdata_i;


wire			mem_wreg_o;
wire[`RegAddrBus]	mem_wd_o;
wire[`RegBus]		mem_wdata_o;


wire			wb_wreg_i;
wire[`RegAddrBus]	wb_wd_i;
wire[`RegBus]		wb_wdata_i;


wire			reg1_read;
wire			reg2_read;
wire[`RegBus]		reg1_data;
wire[`RegBus]		reg2_data;
wire[`RegAddrBus]	reg1_addr;
wire[`RegAddrBus]	reg2_addr;

wire[5:0] stall;
wire stallreq_from_id;
wire stallreq_from_ex;


wire[`DoubleRegBus]	ex_div_result_i;
wire			ex_div_ready_i;

wire[`RegBus]		ex_div_opdata1_o;
wire[`RegBus]		ex_div_opdata2_o;
wire			ex_div_start_o;
wire			ex_signed_div_o;

// just for link branch info
wire			ctrl_branch_flag_o;
wire[`RegBus]		ctrl_branch_target_address_o;
wire[`RegBus]		id_link_address_o;
wire[`RegBus]		ex_link_address_i;

wire[`RegBus]		id_branch_op1_o;
wire[`RegBus]		id_branch_op2_o;
wire[`RegBus]		ex_branch_op1_i;
wire[`RegBus]		ex_branch_op2_i;

wire			ex_branch_flag_o;
wire[`RegBus]		ex_branch_target_o;


wire[`AluOpBus]		mem_aluop_i;
wire[`RegBus]		mem_mem_addr_i;
wire[`RegBus]		mem_reg2_i;

wire			ctrl_flush_inst_o;

	pc_reg pc_reg0(
		.clk(clk),
		.rst(rst),
		.stall(stall),
		.branch_flag_i(ctrl_branch_flag_o),
		.branch_target_address_i(ctrl_branch_target_address_o),
		.pc(pc),
		.ce(rom_ce_o)
	);

	assign rom_addr_o = pc;

	if_id if_id0(
		.clk(clk),
		.rst(rst),
		.stall(stall),
		.if_pc(pc),
		.if_inst(rom_data_i),
		.flush_inst_i(ctrl_flush_inst_o),
		.id_pc(id_pc_i),
		.id_inst(id_inst_i)
	);

	id id0(
		.rst(rst),
		.pc_i(id_pc_i),
		.inst_i(id_inst_i),
		.reg1_data_i(reg1_data),
		.reg2_data_i(reg2_data),
		.ex_wreg_i(ex_wreg_o),
		.ex_wdata_i(ex_wdata_o),
		.ex_wd_i(ex_wd_o),
		.mem_wreg_i(mem_wreg_o),
		.mem_wdata_i(mem_wdata_o),
		.mem_wd_i(mem_wd_o),
		.reg1_read_o(reg1_read),
		.reg2_read_o(reg2_read),
		.reg1_addr_o(reg1_addr),
		.reg2_addr_o(reg2_addr),

		.inst_o(id_inst_o),

		.aluop_o(id_aluop_o),
		.alusel_o(id_alusel_o),
		.reg1_o(id_reg1_o),
		.reg2_o(id_reg2_o),
		.branch_target_op1_o(id_branch_op1_o),
		.branch_target_op2_o(id_branch_op2_o),
		.wd_o(id_wd_o),
		.wreg_o(id_wreg_o),
		.link_address_o(id_link_address_o),
		.stallreq(stallreq_from_id)
	);

	regfile regfile0(
		.clk(clk),
		.rst(rst),
		.we(wb_wreg_i),
		.waddr(wb_wd_i),
		.wdata(wb_wdata_i),
		.re1(reg1_read),
		.raddr1(reg1_addr),
		.rdata1(reg1_data),
		.re2(reg2_read),
		.raddr2(reg2_addr),
		.rdata2(reg2_data)
	);


	id_ex id_ex0(
		.clk(clk),
		.rst(rst),
		.stall(stall),

		.id_inst(id_inst_o),

		.id_aluop(id_aluop_o),
		.id_alusel(id_alusel_o),
		.id_reg1(id_reg1_o),
		.id_reg2(id_reg2_o),
		.branch_target_op1_i(id_branch_op1_o),
		.branch_target_op2_i(id_branch_op2_o),
		.id_wd(id_wd_o),
		.id_wreg(id_wreg_o),
		.flush_inst_i(ctrl_flush_inst_o),
		.id_link_address(id_link_address_o),

		.ex_inst(ex_inst_i),
		.ex_aluop(ex_aluop_i),
		.ex_alusel(ex_alusel_i),
		.ex_reg1(ex_reg1_i),
		.ex_reg2(ex_reg2_i),
		.branch_target_op1_o(ex_branch_op1_i),
		.branch_target_op2_o(ex_branch_op2_i),
		.ex_wd(ex_wd_i),
		.ex_wreg(ex_wreg_i),
		.ex_link_address(ex_link_address_i)
	);

	ex ex0(
		.rst(rst),
		.inst_i(ex_inst_i),
		.aluop_i(ex_aluop_i),
		.alusel_i(ex_alusel_i),
		.reg1_i(ex_reg1_i),
		.reg2_i(ex_reg2_i),
		.branch_target_op1_i(ex_branch_op1_i),
		.branch_target_op2_i(ex_branch_op2_i),
		.wd_i(ex_wd_i),
		.wreg_i(ex_wreg_i),

		.div_result_i(ex_div_result_i),
		.div_ready_i(ex_div_ready_i),
		.link_address_i(ex_link_address_i),

		.wd_o(ex_wd_o),
		.wreg_o(ex_wreg_o),
		.wdata_o(ex_wdata_o),

		.div_opdata1_o(ex_div_opdata1_o),
		.div_opdata2_o(ex_div_opdata2_o),
		.div_start_o(ex_div_start_o),
		.signed_div_o(ex_signed_div_o),

		.aluop_o(ex_aluop_o),
		.mem_addr_o(ex_mem_addr_o),
		.reg2_o(ex_reg2_o),

		.stallreq(stallreq_from_ex),
		.branch_flag_o(ex_branch_flag_o),
		.branch_target_address_o(ex_branch_target_o)
	);

	div div0(
		.clk(clk),
		.rst(rst),
		.signed_div_i(ex_signed_div_o),
		.opdata1_i(ex_div_opdata1_o),
		.opdata2_i(ex_div_opdata2_o),
		.start_i(ex_div_start_o),
		.annual_i(1'b0),
		.result_o(ex_div_result_i),
		.ready_o(ex_div_ready_i)
	);

	ex_mem ex_mem0(
		.clk(clk),
		.rst(rst),
	
		.stall(stall),
		.ex_wd(ex_wd_o),
		.ex_wreg(ex_wreg_o),
		.ex_wdata(ex_wdata_o),

		.ex_aluop(ex_aluop_o),
		.ex_mem_addr(ex_mem_addr_o),
		.ex_reg2(ex_reg2_o),

		.mem_wd(mem_wd_i),
		.mem_wreg(mem_wreg_i),
		.mem_wdata(mem_wdata_i),

		.mem_aluop(mem_aluop_i),
		.mem_mem_addr(mem_mem_addr_i),
		.mem_reg2(mem_reg2_i)
	);


	mem mem0(
		.rst(rst),
		.wd_i(mem_wd_i),
		.wreg_i(mem_wreg_i),
		.wdata_i(mem_wdata_i),

		.aluop_i(mem_aluop_i),
		.mem_addr_i(mem_mem_addr_i),
		.reg2_i(mem_reg2_i),

		.mem_data_i(ram_data_i),

		.wd_o(mem_wd_o),
		.wreg_o(mem_wreg_o),
		.wdata_o(mem_wdata_o),

		.mem_addr_o(ram_addr_o),
		.mem_we_o(ram_we_o),
		.mem_sel_o(ram_sel_o),
		.mem_data_o(ram_data_o),
		.mem_ce_o(ram_ce_o)
	);


	mem_wb mem_wb0(
		.clk(clk),
		.rst(rst),
		.stall(stall),
		.mem_wd(mem_wd_o),
		.mem_wreg(mem_wreg_o),
		.mem_wdata(mem_wdata_o),

		.wb_wd(wb_wd_i),
		.wb_wreg(wb_wreg_i),
		.wb_wdata(wb_wdata_i)
	);

	ctrl ctrl0(
		.rst(rst),
		.branch_flag_i(ex_branch_flag_o),
		.branch_target_address_i(ex_branch_target_o),
		.stallreq_from_id(stallreq_from_id),
		.stallreq_from_ex(stallreq_from_ex),
		.stall(stall),
		.branch_flag_o(ctrl_branch_flag_o),
		.flush_inst_o(ctrl_flush_inst_o),
		.branch_target_address_o(ctrl_branch_target_address_o)
	);

endmodule
